文字列のセンタリング
Posted feedbacks - Nested
Flatten Hidden一番乗りかな?きわめてけれんみのない実装。
Dan the Perl Monger
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | #!/usr/local/bin/perl
use strict;
use warnings;
sub center{
my $str = shift;
my $width = shift || 80;
my $margin = int(($width - length($str))/2);
return $str if $margin == 0;
return " " x int($margin) . $str if $margin > 0;
substr($str, 0, -$margin, '');
return substr($str, 0, $width);
}
chomp and print center($_, 72), "\n" for(<>)
__END__
0 1 2 3 4 5 6 7
012345678901234567890123456789012345678901234567890123456789012345678901
This line is intentionally longer than 72 chars to test center() works fine.
|
substr()二度もやるのは無駄じゃん。
Dan the Lazier
1 2 3 4 5 6 7 8 9 10 | --- center.pl.orig 2007-11-17 04:35:53.000000000 +0900
+++ center.pl 2007-11-17 05:17:39.000000000 +0900
@@ -8,8 +8,7 @@
my $margin = int(($width - length($str))/2);
return $str if $margin == 0;
return " " x int($margin) . $str if $margin > 0;
- substr($str, 0, -$margin, '');
- return substr($str, 0, $width);
+ return substr($str, -$margin, $width);
}
|
これまたけれんみのない、#4120と同様の実装。rubyらしくStringを拡張して格調高く。
Dan the Occasional Rubyist
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 | class String
def centered(width)
width ||= 80
margin = (width - self.length)/2;
return self if margin == 0
return " " * margin + self if margin > 0
self[-margin..margin-1]
end
end
ARGF.readlines.each{|l| puts l.centered(72) }
__END__
0 1 2 3 4 5 6 7
012345678901234567890123456789012345678901234567890123456789012345678901
This line is intentionally longer than 72 chars to test String#centered works fine.
|
また,入力行がちょうどwidth文字 + \nのときに,頭の一文字と\nを切り落としてしまっていたので,centeredに渡す前にchompするようにしました.
1 2 3 4 5 6 7 8 9 10 11 12 13 | class String
def centered(width = 80)
margin = (width - self.length)/2;
return center(width) if margin >= 0
self[-margin..margin-1]
end
end
ARGF.readlines.each{|l| puts l.chomp.centered(72) }
__END__
0 1 2 3 4 5 6 7
012345678901234567890123456789012345678901234567890123456789012345678901
This line is intentionally longer than 72 chars to test String#centered works fine.
|
さらに修正しました. #4173 で,ご指摘を受けた不具合も直っています.
p "0123456789".centered(3) # "345"
p "012".centered(5) # " 012 "
p "012".centered(4) # "012 "
p "012".centered(3) # "012"
p "012".centered(2) # "01"
p "012".centered(1) # "1"
p "012".centered(0) # ""
1 2 3 4 5 6 7 8 9 10 11 12 | class String
def centered(width = 80)
return center(width) if width > size
self[(size - width) / 2, width]
end
end
ARGF.readlines.each{|l| puts l.chomp.centered(72) }
__END__
0 1 2 3 4 5 6 7
012345678901234567890123456789012345678901234567890123456789012345678901
This line is intentionally longer than 72 chars to test String#centered works fine.
|
String#centerは右側からパディングを入れるようですので,それにあわせて,widthをはみ出す場合は「左側から削る」ようにしました.
Rubyでは,(CやPerlと異なり)負の整数の除算の場合,剰余の符号が除数(divisor)の符号と一致するような商が得られますが,4行目で文字列を削る際にその性質を利用しています. (4171 を見てぱくりました.勉強になります:-)
p "0123456789".centered(3) # "456" p "012".centered(5) # " 012 " p "012".centered(4) # "012 " p "012".centered(3) # "012" p "012".centered(2) # "12" p "012".centered(1) # "1" p "012".centered(0) # "" p "012".centered(-1) # "012" p "012".center(4) == " 012 ".centered(4) # true
1 2 3 4 5 6 7 8 9 10 11 | --- center.rb.orig 2007-11-19 17:17:47.000000000 +0900
+++ center.rb 2007-11-19 17:17:39.000000000 +0900
@@ -1,7 +1,7 @@
class String
def centered(width = 80)
- return center(width) if width > size
- self[(size - width) / 2, width]
+ return center(width) if width > size or 0 > width
+ self[-((width - size) / 2), width]
end
end
|
(width.odd? xor self.odd?) のときに、余計に1文字削ってしまうと思います。
1 | p "0123456789".centered(3) => "45"
|
Pythonは組み込みでstr#center()を持ってたりするので一番楽かも。
Dan the Occasional Pythonista
P.S. perl の while(<>)、RubyのARGV.readlinesの代わりってpythonでどう書くのかにゃ?
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | #!/usr/bin/python
def center_and_crop(str, width = 80):
margin = (width - len(str))/2
if margin >= 0: return str.center(width)
else: return str[-margin:width-margin]
if __name__ == '__main__':
import sys
for line in sys.stdin:
print center_and_crop(line[:-1], 72)
# 1 2 3 4 5 6 7
#12345678901234567890123456789012345678901234567890123456789012345678901
#This line is intentionally longer than 72 chars to test center_and_crop works \
fine.
|
初投稿です。 アカウントを作ってログインしようとしたら This account is inactive. と言われてしまいました。 何でだろう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | (use srfi-13)
(define (string-pad-both string width)
(let* ((slen (string-length string))
(left (string-take string (quotient slen 2)))
(right (string-drop string (quotient slen 2)))
(llen (quotient width 2))
(rlen (- width llen)))
(string-append
(string-pad left llen)
(string-pad-right right rlen))))
(define (center string . args)
(string-pad-both string (get-optional args 80)))
|
ごめんなさい。ログインできました。 メールが届いてるのに気づきませんでした。 英語のメッセージを真面目に読んでいなかったせい?
投稿者を修正しておきました。
気づくのが遅れてしまいましたが、修正ありがとうございました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | import std.stdio;
import std.string;
import std.utf;
string cropCenter(string str, uint width){
auto wstr = toUTF16(str);
int leftMargin = cast(int)(width - wstr.length) / 2;
int rightMargin = cast(int)(width - wstr.length) - leftMargin;
return (rightMargin < 0) ?
toUTF8(wstr[-leftMargin..($ + rightMargin)]) :
(repeat(" ", leftMargin) ~ str ~ repeat(" ", rightMargin));
}
void main(){
writefln(cropCenter("ほげら", 2)); //=> "ほげ"
writefln(cropCenter("ほげら", 1)); //=> "げ"
writefln(cropCenter("ほげ", 2)); //=> "ほげ"
writefln(cropCenter("ほげ", 1)); //=> "ほ"
writefln(cropCenter("ほげら", 5)); //=> " ほげら "
writefln(cropCenter("ほげら", 4)); //=> "ほげら "
writefln(cropCenter("ほげ", 5)); //=> " ほげ "
writefln(cropCenter("ほげ", 4)); //=> " ほげ "
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 | using System;
static class Program {
static void Main() {
string[] texts = {
"0123456789",
"abc",
"abcdefg",
"abcdefghijklmn",
};
foreach(string text in texts) {
Console.WriteLine(Centering(text, 10));
}
}
static string Centering(string text, int width) {
int margin = (int)((width - text.Length) / 2);
if (margin == 0)
return text;
if (0 < margin)
return text.PadLeft(margin + text.Length);
return text.Substring(-margin, width);
}
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 | def centering(lst,n)
return lst if (n <= 0 || lst == "")
c = (lst = " "*n + lst + " "*n).size/2
lst[c-n/2..-1][0..n-1]
end
if __FILE__ == $0
p (s = centering("end",4)) != " end" ? s : :ok
p (s = centering("end",3)) != "end" ? s : :ok
p (s = centering("end",2)) != "en" ? s : :ok
p (s = centering("end",1)) != "n" ? s : :ok
p (s = centering("end",0)) != "end" ? s : :ok
p (s = centering("end",-1)) != "end" ? s : :ok
p (s = centering("",0)) != "" ? s : :ok
p (s = centering("",1)) != "" ? s : :ok
end
|
CL の format で。もっときれいに書けそうですが。
1 2 3 4 5 | (defun center (str &optional (width 80))
(let ((margin (- (length str) width)))
(if (> margin 0)
(format t "~a" (subseq str (floor (/ margin 2)) (+ width (floor (/ margin 2)))))
(format t (format nil "~~~a:@<~~a~~>" width) str))))
|
最後の行みたいなときは V を使うと短くなりますよ (format t "~V:@<~A~>" width str)
kozima さん、ご指摘感謝です。 format での~v ってよく調べたら基本的機能なのですね。参考になりました。
1 2 3 4 5 6 | (defun center (str &optional (width 80))
(let ((margin (- (length str) width)))
(format t "~v:@<~a~>" width
(if (> margin 0)
(subseq str (floor (/ margin 2)) (+ width (floor (/ margin 2))))
str))))
|
1 2 3 4 5 6 7 8 9 10 11 12 13 | | centeredOf |
centeredOf := [:line :width |
| size offset centered start end delta |
size := line size.
delta := (width - size + 1) // 2.
offset := (delta min: 0) negated + 1.
start := (delta max: 0) + 1.
end := delta + size min: width.
centered := String new: width withAll: Character space.
centered replaceFrom: start to: end with: line startingAt: offset].
centeredOf value: '123456789' value: 15. "=> ' 123456789 ' "
centeredOf value: '123456789' value: 5. "=> '34567' "
|
特にひねりはありません。さらに簡単にできそうな気がします。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 | #include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *center( char *str, int width, char *out ){
int len,margin,i=0;
char *p = out;
if( !out ){
return NULL;
}
len = strlen(str);
margin = (abs(width-len)+1)/2;
if( margin == 0 || len > width ){
strncpy( p, &str[margin], width );
}
else{
while( i++ < margin ) *p++ = ' ';
strcpy( p, str );
p += len;
while( i++ < width - len + 1 ) *p++ = ' ';
}
return out;
}
int main ( int argc, char *argv[] ){
int n;
char *out;
if( argc < 3 ){
fprintf(stderr, "usage: %s str num\n", argv[0]);
return EXIT_FAILURE;
}
n = atoi( argv[2] );
if( n <= 0 || (out = malloc( sizeof(char)*n )) == NULL ){
return EXIT_FAILURE;
}
printf("%s#\n", center( argv[1], n, out ) );
free(out);
return EXIT_SUCCESS;
}
|
ヌル文字が足りず、変なオマケが後に付きます。
mallocの実装によって気づかないことがあるかもしれません。
私の場合は#が出力されました。丁寧に範囲外の1byteめに'#'をセットしてくれているようです。
PC-E500のベーシックで書いたなこんなの。
今は、schemeで。
実行結果
------
$ gosh 87.scm
1234567890
abc
abcdef
abcdefg
bcdefghijk
-------
奇数文字の時は、右に寄ります。
1 2 3 4 5 6 7 8 9 10 11 12 | (define (centering s w)
(let* ((p (make-string (quotient w 2) #\ ))
(ss (string-append p s p))
(sw (string-length ss))
(mg (quotient (- sw w) 2)))
(substring ss mg (- sw mg))))
(print "1234567890")
(print (centering "abc" 10))
(print (centering "abcdef" 10))
(print (centering "abcdefg" 10))
(print (centering "abcdefghijkl" 10))
|
if文もcenterメソッドも使わずに。
1 2 3 4 5 | def center(s, n):
return (' ' * n + a + ' ' * n)[(len(a)+n)/2:][:n]
print center('abc', 9)
print center('abc', 1)
|
短くて素敵ー。 sがaになってますよ。
あ、ほんとだ。ご指摘感謝です。
1 2 3 4 5 6 7 8 9 10 11 12 13 | function center(s, w) {
var r=[], d=w-s.length;
if (d < 0) { s=s.substring(d/2*-1, s.length+d/2); }
for (var i=0; i<=d/2-1; i++) { r.push(" "); }
r.push(s);
for (var i=0; i<=d/2-1+d%2; i++) { r.push(" "); }
return r.join("");
}
console.log("[" + center("test", 0) + "]"); // => []
console.log("[" + center("test", 5) + "]"); // => [test ]
console.log("[" + center("test", 6) + "]"); // => [ test ]
console.log("[" + center("test", 10) + "]"); // => [ test ]
console.log("[" + center("testtest", 10) + "]"); // => [ testtest ]
|
> for(s in c("1234567890", "abc", "abcdef", "abcdefg", "abcdefghijkl")){
+ print(center(s, 10))
+ }
[1] "1234567890"
[1] " abc "
[1] " abcdef "
[1] " abcdefg "
[1] "bcdefghijk"
1 2 3 | center <- function(s, n){
format(substring(s, (i<-(nchar(s)-n)/2+1), i+n-1), width=n, justify="centre")
}
|
Javaがなかったので初投稿です。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | public class Answer87 {
public static String formatCenter(String str, int length) {
if (length <= 0) return str;
StringBuilder builder = new StringBuilder(str);
for (int index = 0; index < length; index++) {
builder.insert(0, ' ');
builder.append(' ');
}
int start = (builder.length() - length) / 2;
return builder.substring(start, start + length);
}
public static void main(String[] args) {
System.out.println(formatCenter("abcde", 5)); // "abcde"
System.out.println(formatCenter("abcde", 7)); // " abcde "
System.out.println(formatCenter("abcde", 8)); // " abcde "
System.out.println(formatCenter("abcde", 1)); // "c"
System.out.println(formatCenter("abcde", 2)); // "bc"
System.out.println(formatCenter("abcde", 0)); // "abcde"
}
}
|
sayはprint lnだと思ってください。 仕様と有ってるのか・・・どうか
1 2 3 4 5 6 7 8 | var src = '123456789'
say( '[' + centering(src,100) + ']' );
say( '[' + centering(src,5) + ']' );
function centering( s , w ){
if( s.length < w ) return space( ( w / 2 - s.length / 2 ) ) + s + space( ( w / 2 - s.length / 2 ) );
else return s.substring( ( s.length - w ) / 2, s.length - ( ( s.length - w ) / 2 ) );
function space (l){ var r = ''; while( r.length < l ) r += ' '; return r; }
}
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | #include <cstdlib>
#include <iostream>
#include <sstream>
#include "boost/format.hpp"
using namespace std;
using namespace boost;
string ¢er( string &str, int width ){
int len = str.length();
if( len > width ){
str = str.substr( (len-width+1)/2, width );
}
ostringstream oss;
oss << "%1$=" << width << "s";
str = ( format(oss.str()) % str ).str();
return str;
}
int main ( int argc, char *argv[] ){
int width( atoi(argv[2]) );
string str( argv[1] );
cout << center( str, width ) << endl;
return EXIT_SUCCESS;
}
|
1 2 3 4 5 6 7 8 9 | center :: Int -> [Char] -> [Char]
center n str | slen < n = center'
| slen > n = clop
| otherwise = str
where
slen = length str
center' = lmargin ++ str ++ rmargin
(lmargin, rmargin) = splitAt ((n-slen) `div` 2) $ replicate (n-slen) ' '
clop = take n $ drop ((slen-n) `div` 2) str
|
1 2 3 4 5 6 7 8 9 10 11 | String.prototype.center = function(width){ var d, s;
return (d = (width |= 0) - this.length) > 0
? (s = Array((d >> 1) + 1).join(' ')) + this + (d & 1 ? s + ' ' : s)
: this.substr(-d >> 1, width);
};
(typeof alert != 'undefined' ? alert :
typeof print != 'undefined' ? print :
function($){ typeof WSH == 'object' && WSH.echo($) })((function(s, f, t){
for(var r = []; f <= t;) r.push(s.center(f++));
return '['+ r.join(']\n[') +']' })('hoge', -1, 8));
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 | begingroupundo;
if ( getconfig( "AutoAdjustOrikaeshi" ) == 2 ) {
#width = windowwidth;
} else {
#width = getconfig( "Orikaeshi" );
}
if ( !selecting ) {
selectall;
} else {
#l1 = seltoplineno;
#l2 = selendlineno;
movetolineno 1, #l1;
beginsel;
movetolineno 1, #l2;
movetolineno linelen2 + 1, #l2;
endsel;
}
$text = gettext( seltopx, seltopy, selendx, selendy, 1 );
delete;
call center $text, #width;
insert $$return;
endgroupundo;
endmacro;
center:
$$result = "";
while( $$1 != "" ) {
##lineLen = strstr( $$1, "\x0d\x0a" );
##isLastLine = ##lineLen == -1;
if ( ##isLastLine ) {
##lineLen = strlen( $$1 );
}
$$line = leftstr( $$1, ##lineLen );
call center_line $$line, ##2;
$$result = $$result + $$return;
$$1 = rightstr( $$1, strlen( $$1 ) - ##lineLen );
if ( !##isLastLine ) {
$$1 = rightstr( $$1, strlen( $$1 ) - strlen( "\x0d\x0a" ) );
$$result = $$result + "\n";
}
}
return $$result;
center_line:
##margin = ##2 - strlen( $$1 );
if ( ##margin >= 0 ) {
$$result = "";
##i = ##margin / 2;
while( ##i > 0 ) {
$$result = $$result + " ";
##i = ##i - 1;
}
$$result = $$result + $$1;
} else {
##idx = -##margin / 2;
call midstr2, $$1, ##idx, ##2;
$$result = $$return;
// ±1バイトとる範囲をずらして、その中から一番長いテキストをとる
if ( strlen( $$result ) < ##2 ) {
call midstr2, $$1, ##idx + 1, ##2;
if ( strlen( $$return ) > strlen( $$result ) ) {
$$result = $$return;
}
if ( strlen( $$result ) < ##2 ) {
call midstr2, $$1, ##idx - 1, ##2;
if ( strlen( $$return ) > strlen( $$result ) ) {
$$result = $$return;
}
}
}
}
return $$result;
midstr2: // マルチバイトを考慮した midstr
$$src = $$1;
##idx = ##2;
##len = ##3;
if ( ##idx < 0 ) {
##idx = 0;
}
if ( ##idx > strlen( $$src ) ) {
##idx = strlen( $$src );
}
if ( ##len < 0 ) {
##len = 0;
}
if ( ##len > strlen( $$src ) - ##idx ) {
##len = strlen( $$src ) - ##idx ;
}
##end = ##idx + ##len;
##i = 0;
$$dest = "";
while( ##i < ##end ) {
##char = ascii( rightstr( $$src, strlen( $$src ) - ##i ) );
##byte = strlen( char( ##char ) );
if ( ( ##i >= ##idx ) && ( ##i + ##byte <= ##end ) ) {
$$dest = $$dest + char( ##char );
}
##i = ##i + ##byte;
}
return $$dest;
|
Emacs Lisp 実行結果: (string-centering "abc" 0) "" (string-centering "abc" 1) "b" (string-centering "abc" 2) "ab" (string-centering "abc" 3) "abc" (string-centering "abc" 4) "abc " (string-centering "abc" 5) " abc " (string-centering "abc" 6) " abc " (string-centering "abc" 7) " abc "
1 2 3 4 5 6 7 8 | (defun string-centering (s c)
(let ((p (lambda (k) (make-string k ? )))
(d (- c (length s))))
(let ((n (/ d 2))
(m (% d 2)))
(if (>= d 0)
(concat (funcall p n) s (funcall p (+ n m)))
(substring s (abs n) (- (length s) (abs (+ n m))))))))
|
1 2 3 4 5 6 7 | (define (string-centering s c)
(define (p k) (make-string k #\ ))
(let ((d (- c (string-length s))))
(receive (n m) (quotient&remainder d 2)
(if (>= d 0)
(string-append (p n) s (p (+ n m)))
(substring s (abs n) (- (string-length s) (abs (+ n m))))))))
|
次に幅から文字列長を引いて2で割り、初めの文字のオフセットを求めます。このとき幅より大きな文字列が渡されるとマイナスになりますが、そのままにしておきます。
最後にオフセットの位置から順番にコピーしますが、作業エリア範囲外の場合は無視します。すると文字列長に関係なく欲しい結果が得られます。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | #include <stdio.h>
#include <string.h>
#define SPACE ' '
//#define SPACE '*'
char *centering(char *out, const char *str, int width){
int i, len, offset;
len = strlen(str);
memset(out, SPACE, width);
out[width] = '\0';
offset = (width - len) / 2;
for(i=0; i<len; i++){
int ind = offset + i;
if(ind >= 0 && ind <width)
out[ind] = str[i];
}
return out;
}
int main(){
char buf[256];
int i;
for(i=1; i<20; i++)
puts(centering(buf, "abcde", i));
return 0;
}
|
空白埋めしてから、部分コピー
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | #include <stdio.h>
#include <string.h>
// dest のサイズは w + 1 以上とする事
char *centering(char *dest, const char *s, size_t w) {
size_t len;
len = strlen(s);
sprintf(dest, "%*s", w, "");
if (len >= w) strncpy(dest, s + (len - w) / 2, w);
else strncpy(dest + (w - len) / 2, s, len);
return dest;
}
int main(void) {
char buff[256];
printf("|%s|\n", centering(buff, "123456789", 15));
printf("|%s|\n", centering(buff, "123456789", 5));
}
|
#4164を見てたら、sprintfを1回呼ぶだけでも出来そうだと思ったので、やってみました。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | #include <stdio.h>
#include <string.h>
char *centering(char *dest, char *s, int w) {
int d = w - strlen(s);
sprintf(dest, "%*s%.*s%*s", ( d >0 ? d/2 : 0 ), "", ( d >0 ? strlen(s) : w ), s + ( d >0 ? 0 : -d/2 ), ( d >0 ? d/2 : 0 ), "" );
return dest;
}
int main(void) {
char buff[256];
printf("|%s|\n", centering(buff, "123456789", 20));
printf("|%s|\n", centering(buff, "123456789", 5));
}
|
"%.*s" で幅制限出来たのか... ただ、d > 0 で d が奇数のときに、1桁足りないようです。 それを踏まえて、自分ならこう書きます。
1 2 3 4 5 6 7 8 | char *centering(char *dest, char *s, int w) {
int d = w - strlen(s);
if (d > 0) sprintf(dest, "%*s%*s", w - d/2, s, d/2, "");
else sprintf(dest, "%.*s", w, s - d/2);
return dest;
}
|
1 2 3 4 | sprintf(dest, "%*s%.*s%*s",
( d>0 ? d - d/2 : 0 ), "",
( d >0 ? strlen(s) : w ), s + ( d >0 ? 0 : -d/2 ),
( d >0 ? d/2 : 0 ), "" );
|
Stringを拡張。 削るときは後ろを優先。
1 2 3 4 5 6 7 8 9 10 | class String
def neko_center (w)
if (d = self.size - w) > 0
#self.gsub(/\A.{#{d/2}}|.{#{(d+1)/2}}\Z/, '')
self[d/2..-d/2-1]
else
self.center(w)
end
end
end
|
1 2 3 4 5 6 7 | let center str width =
let len = String.length str in
if width>len then
let res = String.make width ' ' in
(String.blit str 0 res ((width-len)/2) len; res)
else
String.sub str ((len-width)/2) width ;;
|
Haskellらしく無限リストと高階関数で。 1. 文字列の右に無限個の空白を連結 2. 左側を揃える 3. 幅の分だけ切り取る
1 2 3 4 5 | center width str = take width . adjust lmargin $ str ++ repeat ' '
where
lmargin = (width - length str) `div` 2
adjust n | n > 0 = (replicate n ' ' ++)
| otherwise = drop (-n)
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 | begingroupundo;
if ( getconfig( "AutoAdjustOrikaeshi" ) == 2 ) {
#width = windowwidth;
} else {
#width = getconfig( "Orikaeshi" );
}
if ( !selecting ) {
#top = 1;
#end = linecount2;
} else {
#top = seltoplineno;
#end = selendlineno;
escape;
}
#i = #top;
while( #i <= #end ) {
movetolineno 1, #i;
#margin = #width - linelen2;
if ( #margin >= 0 ) {
#j = #margin / 2;
$margin = "";
while( #j > 0 ) {
$margin = $margin + " ";
#j = #j - 1;
}
insert $margin;
} else {
beginsel;
movetolineno linelen2 + 1, #i;
$text = gettext( seltopx, seltopy, selendx, selendy, 1 );
delete;
call cutstr, $text, #width;
insert $$return;
}
#i = #i + 1;
}
endgroupundo;
endmacro;
cutstr:
$$src = $$1;
##width = ##2;
if ( ##width < 0 ) {
##width = 0;
}
if ( ##width > strlen( $$src ) ) {
##width = strlen( $$src );
}
##start = strlen( $$src ) - ##width;
##end = strlen( $$src ) + ##width;
##i = 0;
$$dest = "";
$$left = "";
$$right = "";
while( ##i * 2 < ##end ) {
##char = ascii( $$src );
##bytes = strlen( char( ##char ) );
if ( ##i * 2 < ##start ) {
$$left = char( ##char );
}
if ( ( ( ##i + ##bytes ) * 2 > ##end ) && ( $$right == "" ) ) {
$$right = char( ##char );
}
if ( ( ##i * 2 >= ##start ) && ( ( ##i + ##bytes ) * 2 <= ##end ) ) {
$$dest = $$dest + char( ##char );
}
$$src = rightstr( $$src, strlen( $$src ) - ##bytes );
##i = ##i + ##bytes;
}
if ( $$right == "" ) {
$$right = char( ascii( $$src ) );
}
if ( strlen( $$dest ) >= ##width ) {
return $$dest;
}
if ( ( strlen( $$left + $$dest ) <= ##width ) && ( $$left != "" ) ) {
return $$left + $$dest;
}
if ( ( strlen( $$dest + $$right ) <= ##width ) && ( $$right != "" ) ) {
return $$dest + $$right;
}
return $$dest;
|
覚えたてのControl.Monad.Fixを使って。
1 2 3 4 5 6 7 8 9 10 | import Control.Monad.Fix
center :: Int -> String -> String
center n = fix (\f x -> g f x)
where g f x | length x1 == n = x1
| length x2 == n = x2
| length x2 > n = f x2
| otherwise = f $ head $ zipWith3 (\x y z -> x ++ y ++ z) [" "] [x] [" "]
where x1 = tail x
x2 = init x1
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 | if ( getconfig( "AutoAdjustOrikaeshi" ) == 2 ) {
#width = windowwidth;
} else {
#width = getconfig( "Orikaeshi" );
}
disabledraw;
begingroupundo;
if ( !selecting ) {
selectall;
}
#i = seltoplineno;
#end = selendlineno;
escape;
while( #i <= #end ) {
movetolineno 1, #i;
#margin = #width - linelen2;
if ( #margin >= 0 ) {
#j = #margin / 2;
while( #j > 0 ) {
insert " ";
#j = #j - 1;
}
} else {
while( linelen2 > #width ) {
golineend2;
backspace;
if ( !linelen2 > #width ) {
break;
}
golinetop2
delete;
}
}
#i = #i + 1;
}
endgroupundo;
enabledraw;
|
明示的算術演算なし、lengthで文字列の長さも測っていない、「そこまでしたからってどうよ」版 ^^; あ。それから、このセンタリングでは空白は前より入り、切り落としは後ろよりになります。 center 2 "a" → "_a" center 3 "a" → "_a_" center 3 "ab" → "_ab" center 4 "ab" → "_ab_" center 3 "abcde" → "bcd" center 4 "abcde" → "bcde" center 3 "abcdef" → "bcd" center 4 "abcdef" → "bcde"
1 2 3 4 5 6 7 8 9 10 11 | center n s = uncurry (c n []) $ halve s
where c 0 a p q = take n (a ++ q)
c i a p q = d (pred i) (head p:a) (tail p) q
d 0 a p q = take n (a ++ q)
d i a p q = c (pred i) a p q
halve s = e (repeat ' ') (s++repeat ' ') s
where e a b [] = (a,b)
e a b c = o (head b:a) (tail b) (tail c)
o a b [] = (a,b)
o a b c = e a b (tail c)
|
1 2 3 4 | def center(s:String, n:int) = {
val pad = List.make(n," ").mkString("")
(pad + s + pad).toList.drop((s.size+n)/2).take(n).mkString("")
}
|
Io で普通に書いてみました。alignCenter があるのできりつめるところだけです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 | Sequence centered := method(width,
margin := (width - self size) / 2
if (margin < 0,
self slice(-margin, self size + margin)
,
self alignCenter(width)
)
)
# なんか手元のだと定義されていないので
Number to := method(i,
Range clone setRange(self, i)
)
0 to(7) foreach(i,
"proto" asMutable centered(i) justSerialized
"" println
)
/* output
""
"o"
"ro"
"rot"
"prot"
"proto"
"proto "
" proto "
*/
|
なでしこで素直に
1 2 3 4 5 6 7 8 9 | "abcdefg"を3でセンタリングして表示
●センタリング(SをNで)
もし(文字数(S)<=N)ならば
文字列センタリング(S,N)で戻る
1の間
Sから1文字右端削除
もし(文字数(S)<=N)ならば,Sで戻る
Sの1から1文字削除
もし(文字数(S)<=N)ならば,Sで戻る
|
馬鹿正直に作ってみました。 あらかじめ条件を洗い出して、最後に処理をまとめて行う、というのが個人的なスタイルです。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 | #include<stdio.h>
#include<string.h>
void centering( char *buffer, int col_num, char* string );
int main( int argc, char *argv[] )
{
char buf[256];
memset( buf, 0, sizeof(buf) );
centering( buf, 10, "abcdefg" );
printf( "%s\n", buf );
centering( buf, 8, "0123456789" );
printf( "%s\n", buf );
centering( buf, 7, "0123456789" );
printf( "%s\n", buf );
return 0;
}
void centering( char *buffer, int col_num, char* string )
{
int copy_len = 0;
int source_index = 0;
int target_index = 0;
/* output initialize (using '@' instead of SPACE for check) */
memset( buffer, '@', col_num );
buffer[col_num] = '\0';
/* length of string for output */
copy_len = strlen( string );
/* check which is longer */
if( copy_len < col_num )
{
int diff = col_num - copy_len;
target_index = diff / 2;
}
else
{
int diff = copy_len - col_num;
source_index = diff / 2;
copy_len = col_num;
}
memcpy( &buffer[target_index], &string[source_index], copy_len );
return;
}
|
身も蓋もなくstring:centreを使いました。
1> c(center).
{ok,center}
2> center:center("center", 20).
" center "
3> center:center("center", 3).
"ent"
1 2 3 4 | -module(center).
-export([center/2]).
center(Str, Len) -> string:centre(Str, Len).
|
文字列の前に指定幅分の空白を足して、文字列長から指定幅を引いて、
その半分を切り下げて、正なら右へ負なら左へローテイトして、
先頭から指定幅を取り出だしています。
('"'&,@,&'"') 1 center '123456789'
"5"
('"'&,@,&'"') 2 center '123456789'
"45"
('"'&,@,&'"') 3 center '123456789'
"456"
('"'&,@,&'"') 4 center '123456789'
"3456"
('"'&,@,&'"') 5 center '123456789'
"34567"
('"'&,@,&'"') 9 center '123456789'
"123456789"
('"'&,@,&'"') 10 center '123456789'
" 123456789"
('"'&,@,&'"') 11 center '123456789'
" 123456789 "
('"'&,@,&'"') 12 center '123456789'
" 123456789 "
1 | center=.4 :'x{.((<.@-:@#)|.])(x#'' ''),y'
|
Mac OS X (PowerPC 32bit) アセンブリで。strcenter.o をリンクして使います。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 | ;; ------------------------------------------------
;; strcenter.s for Mac OS X (PowerPC 32bit)
;; % as -o strcenter.o strcenter.s
;; ------------------------------------------------
.machine ppc
.globl _strcenter
;; char *strcenter(char *dest, const char *s, size_t width)
;;
;; r3: char *dest
;; r4: const char *s
;; r5: size_t width
;;
;; r7: 文字列 s のサイズ
;; r8: 文字列の前のスペースのサイズ
;; r9: 文字列の後のスペースのサイズ
;; r10: スペースのASCIIコード
;; r11: r3 のコピー
;; r12: r4 のコピー
;;
_strcenter:
;; 初期化
li r7, 0
li r10, 32 ; ' '
mr r11, r3
mr r12, r4
b _strlen
_init_sizes:
;; 基準となるスペースのサイズ
sub r2, r5, r7 ; r2 = width - strlen(s)
li r0, 2
divw r2, r2, r0 ; r2 = r2 / 2
;; 余り
sub r0, r5, r7 ; r0 = width - strlen(s)
andi. r0, r0, 1
;; 前後のスペースのサイズを決定、コピー
add r8, r2, r0 ; 余りがあれば前のスペースに追加
addi r9, r2, 0
;; 基準のスペースのサイズが負の場合
cmpi cr7, r2, 0
blt cr7, _shorten_strcenter
;; 前のスペースをコピー
_copy_former_spaces:
stb r10, 0(r11)
addi r11, r11, 1
subi r8, r8, 1
cmpli cr7, r8, 0
bgt cr7, _copy_former_spaces
;; 文字列をコピー
_copy_str:
lbz r0, 0(r12)
stb r0, 0(r11)
addi r11, r11, 1
addi r12, r12, 1
subi r7, r7, 1
cmpli cr7, r7, 0
bgt cr7, _copy_str
;; 後のスペースをコピー
_copy_latter_spaces:
stb r10, 0(r11)
addi r11, r11, 1
subi r9, r9, 1
cmpli cr7, r9, 0
bgt cr7, _copy_latter_spaces
;; 終端をコピーして終了
_end_strcenter:
li r0, 0
stb r0, 0(r11)
blr ; 関数を終了
;; 文字列の前後をカットしてコピー
_shorten_strcenter:
sub r12, r12, r8 ; 文字列の前半をカット
add r7, r7, r8
add r7, r7, r9 ; 文字列の後半をカット
_copy_shorten_str:
lbz r0, 0(r12)
stb r0, 0(r11)
addi r11, r11, 1
addi r12, r12, 1
subi r7, r7, 1
cmpli cr7, r7, 0
bgt cr7, _copy_shorten_str
b _end_strcenter
_strlen:
mr r2, r4
li r7, 0
__strlen:
lbz r0, 0(r2) ; 1文字レジスタに移す
cmpli cr7, r0, 0
beq cr7, _init_sizes
addi r2, r2, 1
addi r7, r7, 1
b __strlen
|
1 2 3 4 5 6 7 8 9 10 11 | fun center s width =
let
open StringCvt
val len = size s
val m = abs (width - len)
val (left, right) = (m div 2, m div 2 + m mod 2)
in
if width < len then substring (s, left, len - left - right)
else (padLeft #" " (left + right + len) o padRight #" " (right + len)) s
end
|
ex)
echo sprintf('<pre>[%s]</pre>', Centering('test', 4));
('test', 4) => [test]
('test', 8) => [ test ]
('test', 5) => [test ]
('test', 2) => [es]
1 2 3 4 5 6 7 8 9 10 11 12 | <?php
function Centering($str, $width)
{
$slen = strlen($str);
if ($slen < $width) {
$str = str_pad($str, $width, ' ', STR_PAD_BOTH);
} else {
$str = substr($str, (int)(($slen - $width)/2), $width);
}
return $str;
}
?>
|
バッチで書いてみました。文字列が半角空白を含まない場合は、引数をダブルクォーテー
ションで括る必要はありません。なお、18行目と20行目の行末に半角空白が 1つあるので
注意してください。
e.g.
C:\>@echo off & (for /l %i in (0,1,7) do center "abcde" %i) & @echo on
[]
[c]
[bc]
[bcd]
[abcd]
[abcde]
[abcde ]
[ abcde ]
遅延環境変数展開を利用しているので、Windows NTでは動作しません。Windows 2000, XP,
2003で動作を確認。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 | :: center.bat
@echo off
setlocal enabledelayedexpansion
set l=0
set m=0
set n=0
set t=%1
set t=%t:"=%
call :length "%t%" l
if %2 gtr %l% (
set /a m=%2-%l%
set /a n=!m!/2
:: パディング
for /l %%i in (1,1,!n!) do set t= !t!
for /l %%i in (1,1,!n!) do set t=!t!
set /a n=!m!%%2
if !n! equ 1 set t=!t!
)
if %l% gtr %2 (
set /a m=%l%-%2
set /a n=!m!/2
:: トリミング
for /l %%i in (1,1,!n!) do set t=!t:~1!
for /l %%i in (1,1,!n!) do set t=!t:~0,-1!
set /a n=!m!%%2
if !n! equ 1 set t=!t:~0,-1!
)
endlocal & echo [%t%]
goto :EOF
:length
setlocal
set i=0
set t=%1
set t=%t:"=%
:loop
set t=%t:~1%
set /a i+=1
if not "%t%" == "" goto loop
endlocal & set %2=%i%
goto :EOF
|
対象文字列の長さによって分岐しています。 露骨すぎてスマートとは言えないでしょう。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 | #runtime "hsp3cl"
#module
#defcfunc spaces int len
if len <= 0 : return ""
sdim s, len + 1
repeat len
poke s, cnt, ' '
loop
return s
#defcfunc centered_text str target, int len
if len <= 0 : return ""
target_length = strlen(target)
result = target
if target_length < len {
result = spaces((len - target_length)/2) + target + spaces((len - target_length + 1)/2)
} else : if target_length > len {
result = strmid(result, (target_length - len)/2, len)
}
return result
#global
s = "*"
repeat 10
mes centered_text(s, 15)
s += " *"
loop
stop
|
より単純なスクリプトです。 まず指定された長さの半角スペース列を用意し、次に文字列をpokeで書きこんでいます。
1 2 3 4 5 6 7 8 9 10 11 | #module
#defcfunc centered_text str _source, int len
if len <= 0 : return ""
source = _source
source_strlen = strlen(source)
sdim result, len + 1
memset result, ' ', len
poke result, limit((len - source_strlen)/2, 0, len/2), strmid(source, limit((source_strlen - len)/2, 0, source_strlen), len)
return result
#global
|
arc> (centering "hoge" 10)
" hoge "
arc> (centering "hogefuga" 5)
"ogefu"
1 2 3 4 5 6 7 | (def mklist (n (o fill nil)) (map (fn (x) fill) (range 1 n)))
(def centering (str length)
(withs (plen (- length (len str)) tlen (abs plen) l (trunc (/ tlen 2)) r (- tlen l))
(if (positive plen)
(string (mklist l #\space) str (mklist r #\space))
(cut str l (- (len str) r)))))
|
PostScript で。 PostScript で文字数単位でやる実用性はほとんど無いでしょうね。 通常はフォント指定して文字列幅を計算、幅にあわせて切り捨てるなり圧縮するなり、でしょうから。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 | %!PS
/FillSpace { % (String) FillSpace (String')
dup length 1 sub 0 1 3 -1 roll {
1 index exch 32 put
} for
} bind def
/Centering { % (String) length Centering (NewString)
dup string FillSpace dup
3 index length 4 -1 roll
2 copy le {
sub neg 2 idiv 4 -1 roll putinterval
} {
2 copy sub 2 idiv
exch 6 -1 roll 3 1 roll getinterval
exch pop 0 exch putinterval
} ifelse
} bind def
% -------------------- Test Code ------------------
(ABC) 10 Centering ==
(ABCDEF) 10 Centering ==
(ABCDEF) 3 Centering ==
(ABCDEF) 6 Centering ==
|
組み込まれている関数で
1 2 | // 例(Stringクラスのメソッド)
"Japanese".center(20)
|
なかなか面白い問題でした。
最初は文字列が指定より長い場合、短かい場合の処理を別々に書いてたのですが、 (空白を)「くわえる」と「削る」以外の部分は共通にできる事に気がつきました。
1 2 3 4 5 6 7 | center n str = let s = (n - length str)
s1 = div s 2
s2 = s - s1
in reverse.format s2.reverse.format s1 $ str
where format n
| n >= 0 =(replicate n ' '++)
|otherwise = drop (-n)
|






nobsun
#4089()
Rating1/3=0.33
文字列を指定のカラム幅にセンタリング配置する関数を示してください。文字列の長さが指定した幅より長い場合には文字列の両端をできるだけ均等に切り落して指定幅に収めてください。1文字は1カラムに収まるものと仮定してかまいません。
[ reply ]